﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;

namespace NGinnBPM.Rules
{
    public class DynObject : IDynObject
    {
        private Dictionary<string, object> _dic = new Dictionary<string, object>();
        public DynObject()
        {
        }

        public DynObject(System.Collections.IDictionary dic)
        {
            foreach (string k in dic.Keys)
                Set(k, dic[k]);
        }

        public DynObject(IDictionary<string, object> dic)
        {
            foreach (string k in dic.Keys)
                Set(k, dic[k]);
        }

        public object Get(string key)
        {
            return _dic[key];
        }

        public void Set(string key, object value)
        {
            if (value is IDictionary<string, object>)
            {
                Set(key, new DynObject((IDictionary<string, object>) value));
            }
            else if (value is System.Collections.IDictionary)
            {
                Set(key, new DynObject((System.Collections.IDictionary)value));
            }
            else
            {
                _dic[key] = value;
            }
        }

        public object Invoke(string member, object[] arguments)
        {
            object v;
            if (!_dic.TryGetValue(member, out v)) throw new Exception("Member not defined: " + member);
            Func<object[], object> f = v as Func<object[], object>;
            if (f != null)
                return f(arguments);
            Action<object[]> act = v as Action<object[]>;
            if (act != null)
            {
                act(arguments);
                return null;
            }
            System.Delegate dlg = v as Delegate;
            if (dlg != null)
                return dlg.DynamicInvoke(arguments);
            throw new Exception("Not a function: " + member);
        }

        public ICollection<string> Fields
        {
            get { return _dic.Keys; }
        }


        public ICollection<string> GetFieldNames()
        {
            return _dic.Keys;
        }

        private static object FromJToken(JToken tok)
        {
            if (tok is JObject)
            {
                return FromJObject((JObject)tok);
            }
            else if (tok is JArray)
            {
                List<object> lst = new List<object>();
                JArray jar = (JArray)tok;
                for (int i = 0; i < jar.Count; i++)
                {
                    lst.Add(FromJToken(jar[i]));
                }
                return lst;
            }
            else if (tok is JProperty)
            {
                throw new NotImplementedException();
            }
            else if (tok is JValue)
            {
                JValue jv = (JValue)tok;
                return jv.Value;
            }
            else throw new Exception("Unsupported token type: " + tok);
        }

        public static DynObject FromJObject(JObject job)
        {
            DynObject dob = new DynObject();
            foreach (JProperty p in job.Properties())
            {
                dob.Set(p.Name, FromJToken(p.Value));
            }
            return dob;
        }
    }
}
